package top.xzxsrq.ffmpeg;

import cn.hutool.core.util.RuntimeUtil;
import lombok.extern.log4j.Log4j2;
import top.xzxsrq.web.download.entity.PageInfo;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;

@Log4j2
public class FFmpegUtils {
    public static String FFMPEG;

    public static final int THREADS_NUMBER = Runtime.getRuntime().availableProcessors();

    /**
     * 固定使用FFmpeg
     * BASE_CMD_FFMPEG[0],
     * BASE_CMD_FFMPEG[1],
     * BASE_CMD_FFMPEG[2],
     */

    public static String[] GET_BASE_CMD_FFMPEG() {
        return new String[]{
                FFMPEG,
                "-threads",
                String.valueOf(THREADS_NUMBER)
        };
    }

    public static String[] getFFmpegCmds(String... args) {
        String[] getBaseCmdFfmpeg = GET_BASE_CMD_FFMPEG();
        String[] cmds = new String[args.length + getBaseCmdFfmpeg.length];
        System.arraycopy(getBaseCmdFfmpeg, 0, cmds, 0, getBaseCmdFfmpeg.length);
        System.arraycopy(args, 0, cmds, getBaseCmdFfmpeg.length, args.length);
        return cmds;
    }

    /**
     * @param fps     帧率
     * @param txtFile 文件名中有单引号，需要将 ' 转义替换为 '\'' 列子：i = i.replaceAll("'", "'\\\\''"); 文件里面每一个行都是：file '文件路径'
     */
    public static Process txtImgWithAudio2Mp4(int fps, String txtFile, String audioFilePath, String outFile) {
        String[] cmds = getFFmpegCmds("-r",
                String.valueOf(fps),
                "-f",
                "concat",
                "-safe",
                "0",
                "-i",
                txtFile,
                "-i",
                audioFilePath,
                "-c:v",
                "libx264",
                "-pix_fmt",
                "yuv420p",
                "-crf",
                "18",
                "-movflags",
                "faststart",
                outFile,
                "-y");
        log.info("歌词合并视频执行的命令：{}", Arrays.toString(cmds));
        return RuntimeUtil.exec(cmds);
    }

    private static Float lineToDuration(String line) {
        //  Duration: 00:23:45.61, start: 1.460422, bitrate: N/A
        // 获取包含视频时长信息的行
        String durationLine = line.split("Duration:")[1].split(",")[0].trim();
        return timeToFloatTime(durationLine);
    }

    private static Float timeToFloatTime(String time) {
        String[] durationParts = time.split(":");
        int hours = Integer.parseInt(durationParts[0].trim());
        int minutes = Integer.parseInt(durationParts[1].trim());
        double seconds = Double.parseDouble(durationParts[2].trim());
        // 计算总秒数
        double totalSeconds = hours * 3600 + minutes * 60 + seconds;
        String durationInSeconds = String.valueOf(totalSeconds);
        return Float.valueOf(durationInSeconds);
    }

    /**
     * 获取视频的长度，单位是秒
     *
     * @param pathOrUrl
     * @return
     */
    public static Float getVideoSeconds(String pathOrUrl) {
        try {
            // 定义远程视频的URL
            // 构建FFmpeg命令
            ProcessBuilder processBuilder = new ProcessBuilder(FFMPEG, "-i", pathOrUrl);
            // 读取FFmpeg的输出信息
            // 创建ProcessBuilder并执行命令
            processBuilder.redirectErrorStream(true);
            Process process = processBuilder.start();
            // 读取FFmpeg命令输出
            BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
            String line;
            String durationInSeconds = null;
            while ((line = reader.readLine()) != null) {
                //  Duration: 00:23:45.61, start: 1.460422, bitrate: N/A
                if (line.contains("Duration:")) {
                    durationInSeconds = String.valueOf(lineToDuration(line));
                }
            }
            reader.close();
            // 打印视频时长
            if (durationInSeconds != null) {
                log.info(pathOrUrl + "--->视频时长：" + durationInSeconds);
                return Float.valueOf(durationInSeconds);
            } else {
                log.error(pathOrUrl + "--->无法获取视频时长。");
                return null;
            }
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }

    private static Float lineToPointDuration(String line) {
        // frame= 1011 fps=5.2 q=-1.0 Lsize=    2917kB time=00:00:42.06 bitrate= 568.0kbits/s speed=0.214x
        String durationLine = line.split("time=")[1].split(" ")[0].trim();
        return timeToFloatTime(durationLine);
    }

    public static float downloadPer(PageInfo pageInfo, String line) {
        if (line.contains("Duration:")) {
            pageInfo.setTotalTime(lineToDuration(line));
        }
        if (line.contains("time=")) {
            pageInfo.setNowTime(lineToPointDuration(line));
        }
        pageInfo.setDownloadPer(pageInfo.getNowTime() / pageInfo.getTotalTime() * 100);
        return pageInfo.getDownloadPer();
    }

    public static Process download(String downloadUrl, String savePath) {
        String[] cmds = getFFmpegCmds("-i",
                downloadUrl,
                "-c",
                "copy",
                "-y",
                "-movflags",
                "faststart", // -movflags faststart 将moov移到最新前面
                savePath);
        log.info("视频下载执行的命令：{}", Arrays.toString(cmds));
        return RuntimeUtil.exec(cmds);
    }

    public static boolean timeEquals(Float a, Float b) {
        if (a == null) {
            return false;
        }
        if (b == null) {
            return false;
        }
        return Math.abs(a - b) < 10;
    }

}
